package com.sfx.admin.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sfx.admin.common.biz.user.UserContext;
import com.sfx.admin.common.convention.exception.ClientException;
import com.sfx.admin.common.enums.GroupErrorCodeEnums;
import com.sfx.admin.dao.entity.GroupDO;
import com.sfx.admin.dao.mapper.IGroupMapper;
import com.sfx.admin.dto.req.GroupSortReqDTO;
import com.sfx.admin.dto.req.GroupUpdateReqDTO;
import com.sfx.admin.dto.req.ShortLinkCreateGroupReqDTO;
import com.sfx.admin.dto.resp.GroupRespDTO;
import com.sfx.admin.remote.ShortLinkActualRemoteService;
import com.sfx.admin.remote.dto.resp.ShortLinkGroupCountRespDTO;
import com.sfx.admin.service.IGroupService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class GroupServiceImpl extends ServiceImpl<IGroupMapper, GroupDO>
        implements IGroupService {


    private final ShortLinkActualRemoteService shortLinkActualRemoteService;

    @Value("${shortLink.group.MaxLimit}")
    private int groupMaxLimit;

    @Override
    public void saveGroup(ShortLinkCreateGroupReqDTO requestParam) {
        saveGroup(UserContext.getUsername(), requestParam.getName());
    }

    @Override
    public void saveGroup(String username, String groupName) {
        // 1. 检查该用户名的分组下有没有超过最大分组大小,如果超过了直接报错
        LambdaQueryWrapper<GroupDO> queryWrapper = Wrappers.lambdaQuery(GroupDO.class)
                .eq(GroupDO::getUsername, username)
                .eq(GroupDO::getName, groupName)
                .eq(GroupDO::getDelFlag, 0);
        List<GroupDO> groupDOList = baseMapper.selectList(queryWrapper);
        if (CollUtil.isNotEmpty(groupDOList) && groupDOList.size() > groupMaxLimit) {
            throw new ClientException(GroupErrorCodeEnums.GROUP_OVER_MAX_LIMIT);
        }
        //  先生成一个唯一的gid
        String gid;
        do {
            gid = RandomUtil.randomNumbers(6);
        } while (!hasGid(username, gid));
        GroupDO groupDO = GroupDO.builder()
                .gid(gid)
                .name(groupName)
                .username(username)
                .sortOrder(0)
                .build();
        // 插入分组
        baseMapper.insert(groupDO);
    }

    /**
     * 主要是修改短链接分组名称
     *
     * @param requestParam 短链接更新对象
     */
    @Override
    public void updateGroup(GroupUpdateReqDTO requestParam) {
        GroupDO groupDO = GroupDO.builder()
                .name(requestParam.getName())
                .build();
        LambdaUpdateWrapper<GroupDO> updateWrapper = Wrappers.lambdaUpdate(GroupDO.class)
                .eq(GroupDO::getUsername, UserContext.getUsername())
                .eq(GroupDO::getGid, requestParam.getGid())
                .eq(GroupDO::getDelFlag, 0);
        baseMapper.update(groupDO, updateWrapper);
    }

    /**
     * 我们短链接可以支持自动拖拽的,我们会根据sortOrder进行排序-->前端给我们排好序了,我们直接返回即可
     *
     * @return 返回分组排序好的短链接分组
     */
    @Override
    public List<GroupRespDTO> listGroup() {
        String currentUsername = UserContext.getUsername(); // 获取当前用户名并存储为变量
        LambdaQueryWrapper<GroupDO> queryWrapper = Wrappers.lambdaQuery(GroupDO.class)
                .eq(GroupDO::getUsername, currentUsername)
                .eq(GroupDO::getDelFlag, 0)
                .orderByDesc(GroupDO::getSortOrder)
                .orderByDesc(GroupDO::getUpdateTime);

        List<GroupDO> groupDOList = baseMapper.selectList(queryWrapper);
        List<String> requestParam = groupDOList.stream().map(GroupDO::getGid).toList();
        List<ShortLinkGroupCountRespDTO> listResult = shortLinkActualRemoteService
                .getGroupShortLinkCount(requestParam).getData();
        if (CollUtil.isEmpty(listResult)) {
            return Collections.emptyList();
        }

        Map<String, Integer> stringIntegerMap =
                listResult.stream().collect(Collectors.toMap(ShortLinkGroupCountRespDTO::getGid, ShortLinkGroupCountRespDTO::getShortLinkCount));
        List<GroupRespDTO> shortLinkGroupRespDTOS = BeanUtil.copyToList(groupDOList, GroupRespDTO.class);
        shortLinkGroupRespDTOS.forEach(each -> {
            each.setShortLinkCount(stringIntegerMap.get(each.getGid()));
        });
        return shortLinkGroupRespDTOS;
    }

    /**
     * 删除短链接分组
     * 这里是逻辑删除
     *
     * @param gid 删除短链接分组请求参数
     */
    @Override
    public void deleteGroup(String gid) {
        LambdaUpdateWrapper<GroupDO> updateWrapper = Wrappers.lambdaUpdate(GroupDO.class)
                .eq(GroupDO::getUsername, UserContext.getUsername())
                .eq(GroupDO::getGid, gid)
                .eq(GroupDO::getDelFlag, 0)
                .set(GroupDO::getDelFlag, 1);
        update(null, updateWrapper);
    }

    /**
     * 前端排好序了,也就是前端sortOrder字段给我们了,我们修改一下数据库就完事了
     *
     * @param requestParam List<GroupSortReqDTO>
     */
    @Override
    public void groupSort(List<GroupSortReqDTO> requestParam) {
        requestParam.forEach(each -> {
            GroupDO groupDO = GroupDO.builder()
                    .sortOrder(each.getSortOrder())
                    .build();
            LambdaQueryWrapper<GroupDO> queryWrapper =
                    Wrappers.lambdaQuery(GroupDO.class)
                            .eq(GroupDO::getGid, each.getGid())
                            .eq(GroupDO::getDelFlag, 0);
            baseMapper.update(groupDO, queryWrapper);
        });
    }

    /**
     * 看看该用户名下有没有该分组标识, 如果没有该标识直接返回true,有就返回false
     *
     * @param username 用户名
     * @param gid      组id
     * @return 该用户名下有没有该分组标识
     */
    private boolean hasGid(String username, String gid) {
        LambdaQueryWrapper<GroupDO> queryWrapper = Wrappers.lambdaQuery(GroupDO.class)
                .eq(GroupDO::getUsername, Optional.ofNullable(username).orElse(UserContext.getUsername()))
                .eq(GroupDO::getGid, gid);
        GroupDO groupDO = baseMapper.selectOne(queryWrapper);
        return groupDO == null;
    }
}